package a13;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.UndeclaredThrowableException;

import java.lang.reflect.Method;

/**
 * 动态代理的本质：
 * 一、动态代理生成一个代理类，调用代理类就好像调用目标类，因此代理类的方法无目标类的方法一样（代理类与目标类
 * 实现同一接口 / 代理类继承目标类，重写相同的方法）
 * 二、增强的逻辑都是由用户自己控制,即实现InvocationHandler/MethodInterceptor. 这个实现类最终会成为代
 * 理类的一部分，每次调用相应的方法时，看似是调用原方法，实际是增强的方法。增强的方法里通过InvocationHandle-
 * r/MethodInterceptor完成整个原始方法和增强逻辑的运转.
 */
public class Proxy extends Target{

    private MethodInterceptor methodInterceptor;

    public Proxy(MethodInterceptor methodInterceptor){
        this.methodInterceptor = methodInterceptor;
    }

    static Method save0;
    static Method save1;
    static Method save2;
    static MethodProxy save0Proxy;
    static MethodProxy save1Proxy;
    static MethodProxy save2Proxy;

    static {
        try {
            save0 = Target.class.getMethod("save");
            save1 = Target.class.getMethod("save", int.class);  //int原来也有class
            save2 = Target.class.getMethod("save", long.class);
            //()表示参数为null (I)表示int的参数 (J)表示long的参数  V表示返回值为void  这个算是比较底层的写法了
            save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");
            save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper");
            save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper");
        } catch (NoSuchMethodException e) {
            throw new UndeclaredThrowableException(e);
        }
    }


    //原始的方法
    public void saveSuper() {
        super.save();
    }
    public void saveSuper(int i) {
        super.save(i);
    }
    public void saveSuper(long j) {
        super.save(j);
    }

    //>>>>>>被增强的的方法
    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this, save0, new Object[0],save0Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this, save1, new Object[]{i},save1Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(long j) {
        try {
            methodInterceptor.intercept(this, save2, new Object[]{j},save2Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}
